#include <ConnectionBroker/clientconnection/WebSocketClientConnection.h>
#include <ConnectionBroker/server/WebSocketServer.h>
#include <sockets/tls.hpp>
#include <websocketpp.hpp>

using namespace ConnectionBroker;

WebSocketServer::WebSocketServer(const ConnectionBroker::ServerSettings& settings, 
                                 boost::shared_ptr<boost::asio::ssl::context> pContext,
                                 serverCallback pDefaultCallback, 
                                 serverCallback pDefaultClientConnectCallback,
                                 serverCallback pDefaultClientDisconnectCallback
                                )
: Server(settings, pDefaultCallback, pDefaultClientDisconnectCallback, pDefaultClientConnectCallback), mContext(pContext)
{
}

WebSocketServer::~WebSocketServer()
{
}

template <typename endpoint_type> void WebSocketServer::webSocketClientRemove(endpoint_type::handler::connection_ptr pCon)
{
   boost::shared_ptr<WebSocketClientConnection<endpoint_type> > pClient = mConnectionClientMap[pCon];
   removeClient(pClient);
   mConnectionClientMap.erase(pCon);
}


template <typename endpoint_type> WebSocketClientConnectionPtr WebSocketServer::webSocketClientFactory(endpoint_type::handler::connection_ptr pCon)
{
   //Create the new client.
   WebSocketClientConnectionPtr<endpoint_type> pClient(new WebSocketClientConnection<endpoint_type>(pCon));

   //Insert the client into the client list.
   addClient(pClient);

   //Insert the record into the connection client map.
   mConnectionClientMap[pCon] = pClient;

   return pClient;
}

template <typename endpoint_type> void WebSocketServer::onMessage(endpoint_type::handler::connection_ptr pCon, const std::string& pMessage)
{
   //Get the client from the connection pointer.
   WebSocketClientConnectionPtr<endpoint_type> pClient = mConnectionClientMap[pCon];

   messageReceived(pClient, pMessage);
}

void WebSocketServer::start()
{
   if(mContext)
   {
      websocketpp::server_tls::handler::ptr handler(new WebSocketServerHandler<websocketpp::server_tls>(this, mContext));
      websocketpp::server_tls endpoint(handler);
      endpoint.alog().unset_level(websocketpp::log::alevel::ALL);
      endpoint.elog().unset_level(websocketpp::log::elevel::ALL);

      endpoint.alog().set_level(websocketpp::log::alevel::CONNECT);
      endpoint.alog().set_level(websocketpp::log::alevel::DISCONNECT);

      endpoint.elog().set_level(websocketpp::log::elevel::RERROR);
      endpoint.elog().set_level(websocketpp::log::elevel::FATAL);
      endpoint.listen(mSettings.port());
   }
   else
   {
      websocketpp::server::handler::ptr handler(new WebSocketServerHandler<websocketpp::server>(this));
      websocketpp::server endpoint(handler);
      endpoint.alog().unset_level(websocketpp::log::alevel::ALL);
      endpoint.elog().unset_level(websocketpp::log::elevel::ALL);

      endpoint.alog().set_level(websocketpp::log::alevel::CONNECT);
      endpoint.alog().set_level(websocketpp::log::alevel::DISCONNECT);

      endpoint.elog().set_level(websocketpp::log::elevel::RERROR);
      endpoint.elog().set_level(websocketpp::log::elevel::FATAL);
      endpoint.listen(mSettings.port());
   }
}

